package com.ds.infra.rpc.autoconfigure.scanner;

import com.ds.infra.rpc.annotation.RpcReference;
import com.ds.infra.rpc.core.loadbalance.LoadBalance;
import com.ds.infra.rpc.core.proxy.ProxyFactory;
import com.ds.infra.rpc.core.transport.client.RpcClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;

/**
 * 作用：负责扫描带有 @RpcReference 注解的字段，并为它们创建代理对象。
 *
 * @author WeiShaoying
 */
@Component
@Slf4j
public class RpcReferenceScanner implements BeanPostProcessor, ApplicationContextAware {

    private ApplicationContext applicationContext; // 通过接口注入

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    @Autowired
    private RpcClient rpcClient;

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        ReflectionUtils.doWithFields(bean.getClass(), field -> {
            RpcReference annotation = field.getAnnotation(RpcReference.class);
            if (annotation != null) {
                LoadBalance loadBalance = applicationContext.getBean(
                        annotation.loadBalance().getBeanName(),
                        LoadBalance.class
                );
                log.info("====RpcReferenceScanner: {} {}", beanName, field.getName());
                // 使用修正后的参数列表
                Object proxy = ProxyFactory.createProxy(
                        field.getType(),
                        rpcClient,
                        annotation.version(),
                        loadBalance,
                        annotation.timeout(),
                        annotation.retries()
                );

                field.setAccessible(true);
                field.set(bean, proxy);
            }
        });
        return bean;
    }

}
